package com_.dxy_test_.cglib_proxy_;

import net.sf.cglib.core.DebuggingClassWriter;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * @Description Cglib类库动态代理测试
 * @Author dangxianyue
 * @Date 2022/9/25 12:37
 */
public class CglibDynamicProxyTest {

    public static void main(String[] args) {
        // 代理类class文件存入本地磁盘方便我们反编译查看源码
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "./code");
        //创建Enhancer对象，类似于JDK动态代理的Proxy类，下一步就是设置几个参数
        Enhancer enhancer = new Enhancer();
        //设置代理类的要继承的类
        enhancer.setSuperclass(Suitor.class);
        //设置回调函数
        enhancer.setCallback(new ProxyEnhancer(new Suitor()));
        //创建代理类
        Suitor _proxy = (Suitor) enhancer.create();
        System.out.println("_proxy_super_class: " + _proxy.getClass().getSuperclass().getName());
        //_proxy: com.bzyd.test.cglib_proxy_.Suitor
        //cglib的代理类为被代理类的子类，这点是和JDK代理的区别
        _proxy.sendLetter("小丽");

        System.out.println("\n\n调用final、static方法测试是否会被代理：");
        _proxy.finalMethod();
        Suitor.staticMethod();
    }

}

/**
 * 追求者，被代理者
 */
class Suitor {

    /**
     * 写情书
     *
     * @param name
     */
    public void writeLetter(String name) {
        System.out.println("写情书：" + name + "，我喜欢你！");
    }

    /**
     * 送情书
     *
     * @param name
     */
    public void sendLetter(String name) {
        //注意和JDK不同之处：
        //Cglib代理是子类继承的方式，即代理类是被代理类的子类
        //若类内调用的方法是private的，则不回被继承，也就不会被代理增强，反之则可以
        //但这里是用原生写法是这样，若Spring AOP中Cglib代理又不一样，类内调用都不能被代理增强
        writeLetter(name);
        System.out.println("送情书：" + name + "，这是有人送你的情书！");
    }

    /**
     * 测试final方法是否会被代理
     */
    public final void finalMethod() {
        System.out.println("final method");
    }

    /**
     * 测试static方法是否会被代理
     */
    public static void staticMethod() {
        System.out.println("static method");
    }

}

/**
 * 代理增强类
 * 封装增强逻辑
 * 实现net.sf.cglib.proxy.MethodInterceptor
 * 相当于JDK代理中的InvocationHandler
 */
class ProxyEnhancer implements MethodInterceptor {

    private Suitor suitor;

    public ProxyEnhancer() {
    }

    public ProxyEnhancer(Suitor suitor) {
        this.suitor = suitor;
    }

    /**
     * 封装增强逻辑
     *
     * @param o           代理对象
     * @param method      被代理对象的方法
     * @param objects     方法入参
     * @param methodProxy 代理方法
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        String s = "writeLetter".equals(method.getName()) ? "写情书" :
                ("sendLetter".equals(method.getName()) ? "送情书" : "");
        System.out.println("增强逻辑【" + s + "】>>>>>>>>>>>>>开始");

        //1、使用methodProxy.invokeSuper，是Cglib中提供的反射，反射的实例是代理对象，即被代理者的子类
        //所以类内调用public方法也会被代理增强
//        Object invoke = methodProxy.invokeSuper(o, objects);

        //2、使用method.invoke是Java的原生反射，反射的实例直接是被代理者，
        //所以类内方法间调用都是调用被代者中的方法，不会被代理增强，Spring AOP中的Cglib就是这种方式
        Object invoke = method.invoke(suitor, objects);
        System.out.println("增强逻辑【" + s + "】>>>>>>>>>>>>>结束");
        return invoke;
    }
}

